home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / SECURITY / MNGLR140 / MANGLER.PAS < prev    next >
Pascal/Delphi Source File  |  1996-05-01  |  53KB  |  1,797 lines

  1. {   Mangler, a program to mangle pascal source files.
  2.     (c) Copyright 1993-1996 by Berend de Boer.
  3.  
  4.     This program is free software for noncommercial users; you can
  5.     redistribute it and/or modify it under the terms of the license,
  6.     stated in de accompanying file LICENSE.TXT.
  7.  
  8.     This program is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.     license for more details.
  12.  
  13.     See the accompanying READ.ME file for information on contacting the
  14.     author.
  15.  
  16.  
  17. $Author: Berend_de_Boer $
  18. $Date: 94/03/19 20:31:37 $
  19. $Revision: 1.35 $
  20.  
  21. Last changes to code:
  22. }
  23.  
  24. {* conditional defines *}
  25.  
  26. {$DEFINE Crunch}                  { do crunch pass }
  27. {$DEFINE DelTmpFiles}             { delete temporary files }
  28. {{$DEFINE ShowProcs}               { show procedures }
  29. {{$DEFINE ShowFreeItem}            { show item being freed }
  30.  
  31. {$X+}
  32. program Mangler;
  33.  
  34. uses
  35.   LexLib,
  36. {$IFDEF Debug}
  37.   BBError, ObjMemory, PMD, MemCheck,
  38. {$ENDIF}
  39.   Objects, Dos;
  40.  
  41.  
  42. const
  43.   Version = '1.40';
  44.  
  45. const
  46.   LineWidth:word = 120;
  47.   Prime = 67099547;
  48.  
  49. const
  50. {* this list should be sorted! *}
  51.   _ABSOLUTE = 1;
  52.   _AND = 2;
  53.   _ARRAY = 3;
  54.   _ASM = 4;
  55.   _ASSEMBLER = 5;
  56.   _BEGIN = 6;
  57.   _CASE = 7;
  58.   _CONST = 8;
  59.   _CONSTRUCTOR = 9;
  60.   _DESTRUCTOR = 10;
  61.   _DIV = 11;
  62.   _DO = 12;
  63.   _DOWNTO = 13;
  64.   _ELSE = 14;
  65.   _END = 15;
  66.   _EXTERNAL = 16;
  67.   _FAR = 17;
  68.   _FILE = 18;
  69.   _FOR = 19;
  70.   _FORWARD = 20;
  71.   _FUNCTION = 21;
  72.   _GOTO = 22;
  73.   _IF = 23;
  74.   _IMPLEMENTATION = 24;
  75.   _IN = 25;
  76.   _INHERITED = 26;
  77.   _INLINE = 27;
  78.   _INTERFACE = 28;
  79.   _INTERRUPT = 29;
  80.   _LABEL = 30;
  81.   _MOD = 31;
  82.   _NEAR = 32;
  83.   _NIL = 33;
  84.   _NOT = 34;
  85.   _OBJECT = 35;
  86.   _OF = 36;
  87.   _OR = 37;
  88.   _PACKED = 38;
  89.   _PRIVATE = 39;
  90.   _PROCEDURE = 40;
  91.   _PROGRAM = 41;
  92.   _PUBLIC = 42;
  93.   _RECORD = 43;
  94.   _REPEAT = 44;
  95.   _SET = 45;
  96.   _SHL = 46;
  97.   _SHR = 47;
  98.   _STRING = 48;
  99.   _THEN = 49;
  100.   _TO = 50;
  101.   _TYPE = 51;
  102.   _UNIT = 52;
  103.   _UNTIL = 53;
  104.   _USES = 54;
  105.   _VAR = 55;
  106.   _VIRTUAL = 56;
  107.   _WHILE = 57;
  108.   _WITH = 58;
  109.   _XOR = 59;
  110.   SEMICOLON = 100;
  111.   CHARACTER_STRING = 101;
  112.   IDENTIFIER = 102;
  113.   DOT = 103;
  114.   DIRECTIVE = 104;
  115.   NUMBER = 105;
  116.   ASSIGNMENT = 106;
  117.   COLON = 107;
  118.   EQUAL = 108;
  119.   LPAREN = 109;
  120.   RPAREN = 110;
  121.   COMMA = 111;
  122.   OTHER = 112;
  123.   DOTDOT = 113;
  124.   GE = 114;
  125.   LE = 115;
  126.   NOTEQUAL = 116;
  127.   _CHAR = 117;
  128.   NEWLINE = 118;
  129.   KEYWORD = 119;
  130.   UPARROW = 120;
  131.   AMPERSAND = 121;
  132.   LBRAC = 122;
  133.   RBRAC = 123;
  134.  
  135. type
  136.   PScopeCol = ^TScopeCol;
  137.  
  138.   PMangleItem = ^TMangleIteM;
  139.   TMangleItem = record
  140.     Name : PString;
  141.     HashedName : PString;
  142.     ScopeCol : PScopeCol;
  143.     ScopeCopy: Boolean;
  144.   end;
  145.  
  146.   TScopeCol = object(TStringCollection)
  147.     Owner: PMangleItem;
  148.     procedure FreeItem(Item : pointer);  virtual;
  149.     procedure Insert(Item : pointer);  virtual;
  150.     function  KeyOf(Item : pointer) : pointer;  virtual;
  151.     function  InsertIntrIdentifier(const Name : string; var Index : integer) : string;
  152.     function  InsertIdentifier(const Name : string; var Index : integer) : string;
  153.     function  AtHashedName(Index : integer) : string;
  154.     function  AtScope(Index : integer) : PScopeCol;
  155.     function  LastScope : PScopeCol;
  156.   end;
  157.  
  158.  
  159.   SectionTypes = (None, Decl, BetweenCaseAndOfDecl,
  160.                   Func, FuncDecl, FuncOuter, FunctionType,
  161.                   CompoundStatement, WithStatement, Inlin, LabelStatement);
  162.  
  163.   PSectionItem = ^TSectionItem;
  164.   TSectionItem = record
  165.     Section : SectionTypes;
  166.     WithPushes,
  167.     OpeningLevel,
  168.     DeclType : integer;
  169.   end;
  170.  
  171.   PSectionCol = ^TSectionCol;
  172.   TSectionCol = object(TStringCollection)
  173.     procedure FreeItem(Item : pointer);  virtual;
  174.   end;
  175.  
  176.   PForwardPointer = ^TForwardPointer;
  177.   TForwardPointer = record
  178.     PointerName,
  179.     TypeName: PString;
  180.   end;
  181.  
  182.   PForwardPointerCol = ^TForwardPointerCol;
  183.   TForwardPointerCol = object(TStringCollection)
  184.     procedure FreeItem(Item: pointer);  virtual;
  185.     function  KeyOf(Item: pointer): pointer;  virtual;
  186.     procedure InsertItem(const APointerName, ATypeName: string);
  187.   end;
  188.  
  189. var
  190.   sourceDir : DirStr;
  191.   DirInfo : SearchRec;
  192.   ExitSave : pointer;
  193.   ImplementationLineNumber : word;
  194.  
  195.  
  196. function HashIt(s : string) : string;
  197. const
  198.   Base = 5;
  199.   chars:array [0..Base-1] of char = ('0', '1', 'I', 'O', 'l');
  200.  
  201.   function StrBase(l : longint) : string;
  202.   var
  203.     s : string;
  204.   begin
  205.     s := '';
  206.     while l > Base-1 do  begin
  207.       s := chars[l mod Base] + s;
  208.       l := l div Base;
  209.     end;  { of while }
  210.     s := chars[l]+ s;
  211.     StrBase := s;
  212.   end;
  213.  
  214. var
  215.   l, d : longint;
  216.   i,j : word;
  217. begin
  218.   l := 0;
  219.   Move(s[1], l, length(s) mod 4);
  220.   j := length(s) mod 4 + 1;
  221.   for i := 1 to length(s) div 4 do  begin
  222.     Move(s[j], d, 4);
  223.     l := l xor d;
  224.     Inc(j, 4);
  225.   end;  { of for }
  226.   HashIt := 'O' + StrBase(Abs(l) mod Prime);
  227. end;
  228.  
  229.  
  230. procedure TScopeCol.FreeItem(Item : pointer);
  231.  
  232.   function AlsoUsesThisScope(Item2 : PMangleItem) : Boolean;  far;
  233.   begin
  234.     AlsoUsesThisScope := (Item2 <> Item) and
  235.                          (Item2^.ScopeCol = PMangleItem(Item)^.ScopeCol);
  236.   end;
  237.  
  238. var
  239.   p : PMangleItem;
  240. begin
  241.   with PMangleItem(Item)^ do  begin
  242.   {$IFDEF ShowFreeItem}
  243.     writeln('Freeing: ', Name^);
  244.   {$ENDIF}
  245.     DisposeStr(Name);
  246.     DisposeStr(HashedName);
  247.     if (ScopeCol <> nil) and (not ScopeCopy) then  begin
  248.     { check if more items use this ScopeCol, don't delete then! }
  249.       p := FirstThat(@AlsoUsesThisScope);
  250.       if p = nil then
  251.         Dispose(ScopeCol, Done);
  252.     end;
  253.   end;
  254.   Dispose(PMangleItem(Item));
  255. end;
  256.  
  257. procedure TScopeCol.Insert(Item : pointer);
  258. var
  259.   Index : integer;
  260. begin
  261.   if Search(KeyOf(Item), Index)
  262.    then  AtPut(Index, Item)
  263.    else  AtInsert(Index, Item);
  264. end;
  265.  
  266. function TScopeCol.KeyOf(Item : pointer) : pointer;
  267. begin
  268.   KeyOf := PMangleItem(Item)^.Name;
  269. end;
  270.  
  271. function TScopeCol.InsertIntrIdentifier(const Name : string; var Index : integer) : string;
  272. var
  273.   p : PMangleItem;
  274. begin
  275.   New(p);
  276.   p^.Name := NewStr(Name);
  277.   p^.HashedName := NewStr(Name);
  278.   p^.ScopeCol := nil;
  279.   Insert(p);
  280.   Index := IndexOf(p);
  281.   InsertIntrIdentifier := p^.Name^;
  282. end;
  283.  
  284. function TScopeCol.InsertIdentifier(const Name : string; var Index : integer) : string;
  285. var
  286.   p : PMangleItem;
  287. begin
  288.   New(p);
  289.   p^.Name := NewStr(Name);
  290.   p^.HashedName := NewStr(HashIt(Name));
  291.   p^.ScopeCol := nil;
  292.   Insert(p);
  293.   Index := IndexOf(p);
  294.   InsertIdentifier := p^.HashedName^;
  295. end;
  296.  
  297. function TScopeCol.AtHashedName(Index : integer) : string;
  298. begin
  299.   AtHashedName := PMangleItem(At(Index))^.HashedName^;
  300. end;
  301.  
  302. function TScopeCol.AtScope(Index : integer) : PScopeCol;
  303. begin
  304.   if Index = -1
  305.    then  AtScope := nil
  306.    else  AtScope := PMangleItem(At(Index))^.ScopeCol;
  307. end;
  308.  
  309. function TScopeCol.LastScope : PScopeCol;
  310. begin
  311.   LastScope := PMangleItem(At(Count-1))^.ScopeCol;
  312. end;
  313.  
  314.  
  315. procedure TSectionCol.FreeItem(Item : pointer);
  316. begin
  317.   Dispose(PSectionItem(Item));
  318. end;
  319.  
  320.  
  321. procedure TForwardPointerCol.FreeItem(Item: pointer);
  322. begin
  323.   with PForwardPointer(Item)^ do  begin
  324.     DisposeStr(PointerName);
  325.     DisposeStr(TypeName);
  326.   end;
  327.   Dispose(PForwardPointer(Item));
  328. end;
  329.  
  330. function TForwardPointerCol.KeyOf(Item: pointer): pointer;
  331. begin
  332.   KeyOf := PForwardPointer(Item)^.TypeName;
  333. end;
  334.  
  335. procedure TForwardPointerCol.InsertItem(const APointerName, ATypeName: string);
  336. var
  337.   p: PForwardPointer;
  338. begin
  339.   New(p);
  340.   p^.PointerName := NewStr(APointerName);
  341.   p^.TypeName := NewStr(ATypeName);
  342.   Insert(p);
  343. end;
  344.  
  345.  
  346. function UpStr(const s : string) : string;  assembler;
  347. asm
  348.   push   ds
  349.   cld
  350.   lds    si,s
  351.   les    di,@Result
  352.   lodsb
  353.   stosb
  354.   xor    ah,ah
  355.   xchg   ax,cx
  356.   jcxz   @3
  357. @1:
  358.   lodsb
  359.   cmp    al,'a'
  360.   jb     @2
  361.   cmp    al,'z'
  362.   ja     @2
  363.   sub    al,20H
  364. @2:
  365.   stosb
  366.   loop   @1
  367. @3:
  368.   pop    ds
  369. end;
  370.  
  371.  
  372.  
  373. procedure WriteProgress;
  374. {* writes current file with current linenumber *}
  375. begin
  376.   write(#13, sourceDir+DirInfo.Name, ' (', yylineno-1, ')');
  377. end;
  378.  
  379. procedure ExitHandler;  far;
  380. begin
  381.   ExitProc := ExitSave;
  382.   if TextRec(yyoutput).Mode <> fmClosed then  begin
  383.     WriteProgress;
  384.     Close(yyoutput);
  385.   end;
  386. end;
  387.  
  388. procedure Halt1;
  389. {* stop program, delete temporary files*}
  390. begin
  391.   {$I-}
  392.   Close(yyoutput);
  393. {$IFDEF DelTmpFiles}
  394.   Erase(yyoutput);
  395.   {$I+}
  396. {$ENDIF}
  397.   Halt(1);
  398. end;
  399.  
  400. procedure commenteof;
  401. begin
  402.   WriteProgress;
  403.   writeln('  unexpected EOF inside comment');
  404.   Halt1;
  405. end;
  406.  
  407. function IsClosed(var t : text) : Boolean;
  408. begin
  409.   IsClosed := TextRec(t).Mode = fmClosed;
  410. end;
  411.  
  412. procedure PrintError(const s : string);
  413. begin
  414.   WriteProgress;
  415.   writeln('  ', s);
  416. end;
  417.  
  418. function is_keyword(const id : string; var token : integer) : Boolean;
  419. const
  420.   id_len = 18;
  421. type
  422.   Ident = string[id_len];
  423. const
  424.   (* table of Pascal keywords: *)
  425.   no_of_keywords = 59;
  426.   keyword : array [1..no_of_keywords] of Ident = (
  427.     'ABSOLUTE', 'AND', 'ARRAY', 'ASM', 'ASSEMBLER', 'BEGIN', 'CASE', 'CONST',
  428.     'CONSTRUCTOR', 'DESTRUCTOR', 'DIV', 'DO',
  429.     'DOWNTO', 'ELSE', 'END', 'EXTERNAL', 'FAR', 'FILE', 'FOR', 'FORWARD',
  430.     'FUNCTION',
  431.     'GOTO', 'IF', 'IMPLEMENTATION', 'IN', 'INHERITED', 'INLINE', 'INTERFACE',
  432.     'INTERRUPT',
  433.     'LABEL', 'MOD', 'NEAR', 'NIL', 'NOT', 'OBJECT', 'OF', 'OR',
  434.     'PACKED', 'PRIVATE', 'PROCEDURE', 'PROGRAM', 'PUBLIC',
  435.     'RECORD', 'REPEAT', 'SET', 'SHL', 'SHR', 'STRING', 'THEN', 'TO', 'TYPE',
  436.     'UNIT', 'UNTIL', 'USES', 'VAR', 'VIRTUAL', 'WHILE', 'WITH', 'XOR');
  437. var m, n, k : integer;
  438. begin
  439.   m := 1; n := no_of_keywords;
  440.   while m<=n do  begin
  441.     k := m+(n-m) div 2;
  442.     if id=keyword[k]
  443.      then  begin
  444.        is_keyword := true;
  445.        token := k;
  446.        Exit;
  447.      end
  448.      else  if id>keyword[k]
  449.             then  m := k+1
  450.             else  n := k-1
  451.   end;  { of while }
  452.   is_keyword := false
  453. end;
  454.  
  455.  
  456. {$I PASLEX.PAS *}
  457.  
  458.  
  459.  
  460. function Scramble(FromFile, ToFile : FNameStr) : Boolean;
  461. {* mangles a given file as much as possible *}
  462. type
  463.   RecordTypes = (rtNone, rtRecord, rtVariantRecord);
  464.   PInteger = ^integer;
  465. var
  466.   LastScopeIndex : integer;
  467.   Section : SectionTypes;
  468.   DeclType : word;
  469.   RecordType : RecordTypes;
  470.   SectionStack : PSectionCol;
  471.   ScopeStack : PCollection;
  472.   CurrentScope : PScopeCol;
  473.   ForwardPointerCol: PForwardPointerCol;
  474.   WithPushes : integer;
  475.   OpeningLevel : integer;
  476.   ParenLevel : word;
  477.   AssemblerSection : Boolean;
  478.   ObjectImpl : Boolean;
  479.   ConstantArray : Boolean;
  480.   TypeCastDetected: Boolean;
  481.  
  482.  
  483.   procedure PushScope(ps : PScopeCol);
  484.   begin
  485.     ScopeStack^.Insert(ps);
  486.   end;
  487.  
  488.   function PopScope : PScopeCol;
  489.   begin
  490.     with ScopeStack^ do  begin
  491.       PopScope := At(Count-1);
  492.       AtDelete(Count-1);
  493.     end;
  494.   end;
  495.  
  496.  
  497.   procedure PushSection(Section : SectionTypes);
  498.   var
  499.     p : PSectionItem;
  500.   begin
  501.     New(p);
  502.     p^.Section := Section;
  503.     p^.WithPushes := WithPushes;
  504.     p^.OpeningLevel := OpeningLevel;
  505.     p^.DeclType := DeclType;
  506.     with SectionStack^ do
  507.       AtInsert(Count, p);
  508.   end;
  509.  
  510.   function PopSection : SectionTypes;
  511.   var
  512.     i : PInteger;
  513.     p : PSectionItem;
  514.   begin
  515.     with SectionStack^ do
  516.       p := At(Count-1);
  517.     DeclType := p^.DeclType;
  518.     OpeningLevel := p^.OpeningLevel;
  519.     WithPushes := p^.WithPushes;
  520.     PopSection := p^.Section;
  521.     with SectionStack^ do
  522.       AtFree(Count-1);
  523.   end;
  524.  
  525.   procedure CreateCurrentScope;
  526.   var
  527.     Item: PMangleItem;
  528.   begin
  529.     CurrentScope := New(PScopeCol, Init(20,10));
  530.     with ScopeStack^ do  begin
  531.       Item := PMangleItem(PScopeCol(At(Count-1))^.At(LastScopeIndex));
  532.       Item^.ScopeCol := CurrentScope;
  533.       CurrentScope^.Owner := Item;
  534.     end;
  535.   end;
  536.  
  537.   function Encode(const s : string) : string;
  538.   var
  539.     Item: PMangleItem;
  540.   begin
  541.   {* create new scope if necessary *}
  542.     if CurrentScope = nil then
  543.       CreateCurrentScope;
  544.  
  545.   {* add identifier to current scope *}
  546.     Encode := CurrentScope^.InsertIdentifier(s, LastScopeIndex);
  547.  
  548.   {* make the current identifier the new scope *}
  549.     PushScope(CurrentScope);
  550.     CurrentScope := CurrentScope^.AtScope(LastScopeIndex);
  551.   end;
  552.  
  553.   function Encode2(const s : string) : string;
  554.   {* as Encode but without setting a new scope *}
  555.   var
  556.     Index: integer;
  557.   begin
  558.     {* create new scope if necessary *}
  559.     if CurrentScope = nil then
  560.       CreateCurrentScope;
  561.  
  562.   {* add identifier to current scope *}
  563.     Encode2 := CurrentScope^.InsertIdentifier(s, Index);
  564.   end;
  565.  
  566.   function EncodeNot2(const s : string) : string;
  567.   {* as Encode but without setting a new scope and without encoding *}
  568.   var
  569.     Index : integer;
  570.   begin
  571.     {* create new scope if necessary *}
  572.     if CurrentScope = nil then
  573.       CreateCurrentScope;
  574.  
  575.   {* add identifier to current scope *}
  576.     EncodeNot2 := CurrentScope^.InsertIntrIdentifier(s, Index);
  577.   end;
  578.  
  579.   function Encode3(const s : string) : string;
  580.   {* inserts identifier in last scope on stack, sets scope of inserted
  581.      identifier equal to current scope *}
  582.   var
  583.     Index : integer;
  584.   begin
  585.     with ScopeStack^, PScopeCol(At(Count-1))^ do  begin
  586.       Encode3 := InsertIdentifier(s, Index);
  587.       PMangleItem(At(Index))^.ScopeCol := CurrentScope;
  588.     end;
  589.   end;
  590.  
  591.   function EncodeNot3(const s : string) : string;
  592.   { inserts identifier in last scope on stack, sets scope of inserted
  593.     identifier equal to current scope, but don't encode }
  594.   var
  595.     Index : integer;
  596.   begin
  597.     with ScopeStack^, PScopeCol(At(Count-1))^ do  begin
  598.       EncodeNot3 := InsertIntrIdentifier(s, Index);
  599.       PMangleItem(At(Index))^.ScopeCol := CurrentScope;
  600.     end;
  601.   end;
  602.  
  603.   function EncodeNot(const s : string) : string;
  604.   {* as Encode, but identifier is not mangled *}
  605.   begin
  606.     {* create new scope if necessary *}
  607.     if CurrentScope = nil then
  608.       CreateCurrentScope;
  609.  
  610.   {* add identifier to current scope *}
  611.     CurrentScope^.InsertIntrIdentifier(s, LastScopeIndex);
  612.     EncodeNot := s;
  613.  
  614.   {* make the current identifier the new scope *}
  615.     PushScope(CurrentScope);
  616.     CurrentScope := CurrentScope^.AtScope(LastScopeIndex);
  617.   end;
  618.  
  619.   function GetScope(const s : string; var Index : integer) : PScopeCol;
  620.   {* returns scope in which s was defined if exists *}
  621.  
  622.     function Containss(Item : PScopeCol) : Boolean;  far;
  623.     begin
  624.       Containss := (Item <> nil) and (Item^.Search(@s, Index));
  625.     end;
  626.  
  627.   begin
  628.     if (CurrentScope <> nil) and CurrentScope^.Search(@s, Index)
  629.      then  GetScope := CurrentScope
  630.      else
  631.      {* search in scopes on ScopeStack *}
  632.        GetScope := ScopeStack^.LastThat(@Containss);
  633.   end;
  634.  
  635.   function GetMangleItem(const Name: string; var Item: PMangleItem): Boolean;
  636.   var
  637.     Scope: PScopeCol;
  638.     Index: integer;
  639.   begin
  640.     Scope := GetScope(Name, Index);
  641.     if Scope = nil
  642.       then
  643.         GetMangleItem := False
  644.       else  begin
  645.         GetMangleItem := True;
  646.         Item := Scope^.At(Index);
  647.       end;
  648.   end;
  649.  
  650.   function GiveEncodingFor(s : string) : string;
  651.   {* DO NOT MAKE s a const string!!! *}
  652.   { PRE -
  653.     POST - contents of yytext is destroyed
  654.   }
  655.   var
  656.     p,d : PScopeCol;
  657.     e : string;
  658.     Index : integer;
  659.   begin
  660.     if yylex = DOT
  661.      then  begin
  662.      {* a dot was used to select a different scope *}
  663.        p := GetScope(s, Index);
  664.        if p = nil
  665.         then  begin     {* an unknown scope was selected *}
  666.           e := s + '.';
  667.           while (yylex = IDENTIFIER) do  begin
  668.             e := e + yytext;
  669.             if yylex = DOT
  670.              then  e := e + '.'
  671.              else  Break;
  672.           end;
  673.           yyless(0);
  674.         end
  675.         else  begin
  676.           PushScope(CurrentScope);
  677.           CurrentScope := p^.AtScope(Index);
  678.           e := p^.AtHashedName(Index) + '.';
  679.           while (yylex = IDENTIFIER) do  begin
  680.             if CurrentScope = nil
  681.              then  begin
  682.                e := e + yytext;
  683. (* why this source??? if nil you don't know anything it seems
  684.                d := GetScope(yytext, Index);
  685.                if d <> nil
  686.                 then  e := e + GiveEncodingFor(yytext)
  687.                 else  e := e + yytext;
  688. *)
  689.              end
  690.              else  begin
  691.                if CurrentScope^.Search(@yytext, Index)
  692.                 then  e := e + CurrentScope^.AtHashedName(Index)
  693.                 else  e := e + yytext;
  694.              end;
  695.             if yylex = DOT
  696.              then  begin
  697.                if CurrentScope <> nil then
  698.                  if CurrentScope^.Count = 0
  699.                   then  CurrentScope := nil
  700.                   else  CurrentScope := CurrentScope^.AtScope(Index);
  701.                e := e + '.';
  702.              end
  703.              else  break;
  704.           end;  { of while }
  705.           yyless(0);
  706.           CurrentScope := PopScope;
  707.         end;
  708.        GiveEncodingFor := e;
  709.      end
  710.      else  begin
  711.        yyless(0);
  712.        p := GetScope(s, Index);
  713.        if p = nil
  714.         then  GiveEncodingFor := s
  715.         else  GiveEncodingFor := p^.AtHashedName(Index)
  716.      end;
  717.   end;
  718.  
  719.  
  720.  
  721.  
  722.  
  723. {$I ASMLEX.PAS}
  724.  
  725. var
  726.   Buffer : array[1..1024] of char;
  727.   GlobalSection : (Un, Intr, Impl);
  728.   RightHand : Boolean;
  729.   ObjectDecl : Boolean;
  730.   Index : integer;           {* scratch variable *}
  731.   ObjectName : string;
  732.   i : integer;               {* scratch varaible *}
  733.   Scope : PScopeCol;         {* scratch variable *}
  734.   TypeDecl,
  735.   AbsoluteParsed : Boolean;
  736.   Paren : integer;
  737.   LastRetVal : integer;      {* previous value of yyretval *}
  738.  
  739.  
  740.   procedure HandleSemiColon;
  741.   var
  742.     i: integer;
  743.     wp: integer;
  744.     Index,
  745.     PointerIndex: integer;
  746.     TypeItem,
  747.     PointerItem: PMangleItem;
  748.   begin
  749.     ConstantArray := FALSE;
  750.     writeln(yyoutput, yytext);
  751.     case GlobalSection of
  752.       Intr : case Section of
  753.                Decl : begin
  754.                    if not ((RecordType = rtVariantRecord) and (LastRetVal = RPAREN)) then
  755.                      RightHand := FALSE;
  756.                    CurrentScope := PopScope;
  757.                  end;
  758.                Func, FunctionType : begin
  759.                    CurrentScope := PopScope;
  760.                    RightHand := FALSE;
  761.                    Section := Decl;
  762.                  end;
  763.                FuncDecl : RightHand := FALSE;
  764.              end; { of case }
  765.       Impl : begin
  766.                case Section of
  767.                  Decl : begin
  768.                      if not ((RecordType = rtVariantRecord) and (LastRetVal = RPAREN)) then
  769.                        RightHand := FALSE;
  770.                      if CurrentScope = nil
  771.                        then
  772.                          TypeItem := nil
  773.                        else
  774.                          TypeItem := CurrentScope^.Owner;
  775.                      CurrentScope := PopScope;
  776.                      if (TypeItem <> nil) and (ForwardPointerCol^.Count > 0) then  begin
  777.                        while ForwardPointerCol^.Search(TypeItem^.Name, Index) do  begin
  778.                          if GetMangleItem(PForwardPointer(ForwardPointerCol^.At(Index))^.PointerName^, PointerItem) then  begin
  779.                             PointerItem^.ScopeCol := TypeItem^.ScopeCol;
  780.                             PointerItem^.ScopeCopy := True;
  781.                          end;
  782.                          ForwardPointerCol^.AtFree(Index);
  783.                        end;
  784.                      end;
  785.                    end;
  786.                  Func : begin
  787.                      if ObjectDecl then  begin
  788.                         CurrentScope := PopScope;
  789.                         Section := Decl;
  790.                      end;
  791.                    end;
  792.                  FunctionType : begin
  793.                      CurrentScope := PopScope;
  794.                      RightHand := FALSE;
  795.                      Section := Decl;
  796.                    end;
  797.                  FuncDecl : RightHand := FALSE;
  798.                  WithStatement : begin
  799.                      wp := WithPushes;
  800.                      for i := 0 to wp-1 do
  801.                        CurrentScope := PopScope;
  802.                      Section := PopSection;
  803.                    end;
  804.                  Inlin : begin
  805.                      Section := PopSection;
  806.                      CurrentScope := PopScope;
  807.                    end;
  808.                  LabelStatement : begin
  809.                      RightHand := FALSE;
  810.                      Section := Decl;
  811.                    end;
  812.                end; { of case }
  813.                if TypeCastDetected then  begin
  814.                  CurrentScope := PopScope;
  815.                  TypeCastDetected := False;
  816.                end;
  817.              end;
  818.     end; { of case }
  819.   end;  { of proc HandleSemiClon *}
  820.  
  821.  
  822.   procedure ParseDeclaration;
  823.   var
  824.     i : integer;
  825.     saveyytext : string;
  826.     OldScope : PScopeCol;
  827.  
  828.     procedure SetNewScope(Item : PMangleItem);  far;
  829.     begin
  830.       if Item^.ScopeCol = OldScope then  begin
  831.         Item^.ScopeCol := CurrentScope;
  832.         Item^.ScopeCopy := True;
  833.       end;
  834.     end;
  835.  
  836.   begin
  837.     if RightHand
  838.      then  begin
  839.        if not AbsoluteParsed then  begin
  840.          Scope := GetScope(yytext, Index);
  841.          if Scope <> nil then  begin
  842.          { variable of mangled types should get the }
  843.  
  844.          { same scope as their type }
  845.            Scope := Scope^.AtScope(Index);
  846.            CurrentScope := Scope;
  847.            with PMangleItem(PScopeCol(ScopeStack^.At(ScopeStack^.Count-1))^.At(LastScopeIndex))^ do  begin
  848.              ScopeCopy := True;
  849.              if ScopeCol = nil
  850.               then  ScopeCol := CurrentScope
  851.               else  begin
  852.                 if ScopeCol^.Count = 0
  853.                  then  begin
  854.                  { scope is not nil for a list of comma seperated variables
  855.                    who all get the same scope. Search these variables and
  856.                    set their ScopeCol to the ScopeCol of their type}
  857.                    OldScope := ScopeCol;
  858.                    PScopeCol(ScopeStack^.At(ScopeStack^.Count-1))^.ForEach(@SetNewScope);
  859.                  end
  860.                  else  begin
  861.                    writeln('Internal error. Scope of ' + Name^ + ' should be nil.');
  862.                    Halt(1);
  863.                  end;
  864.               end;
  865.            end; { of with }
  866.          end;
  867.        end;
  868.        write(yyoutput, GiveEncodingFor(yytext));
  869.      end
  870.      else  begin
  871.        ObjectName := yytext;
  872.        AbsoluteParsed := FALSE;
  873.  
  874.      {* check if constant array variable is specified *}
  875.        if (DeclType = _CONST) and (not RightHand) then  begin
  876.          saveyytext := yytext;
  877.          if (yylex = COLON) or (yyretval = EQUAL)
  878.           then  begin
  879.             yyless(0);
  880.             yytext := saveyytext;
  881.           end
  882.           else  begin
  883.             yyless(0);
  884.             write(yyoutput, GiveEncodingFor(saveyytext));
  885.             ConstantArray := TRUE;
  886.             Exit;
  887.           end;
  888.        end;
  889.  
  890.      { if we are in the interface section, don't encode }
  891.        if GlobalSection = Intr
  892.         then  write(yyoutput, EncodeNot(yytext))
  893.         else
  894.         {* encode the lefthand *}
  895.           write(yyoutput, Encode(yytext));
  896.  
  897.      { create new scope if COMMA detected, set ConstantRecord if COLON }
  898.        if yylex = COMMA then begin
  899.          CreateCurrentScope;
  900.        end;
  901.        yyless(0);
  902.        if yyretval = COMMA then  begin
  903.          repeat
  904.            if yylex = COMMA
  905.             then  begin
  906.               write(yyoutput, ',');
  907.               yylex;
  908.               if GlobalSection = Intr
  909.                then  write(yyoutput, EncodeNot3(yytext))
  910.                else  write(yyoutput, Encode3(yytext));
  911.             end
  912.             else  break;
  913.          until false;
  914.          yyless(0);
  915.        end;
  916.      end;
  917.   end; { of ParseDeclaration }
  918.  
  919.  
  920.   procedure ParseFunctionDeclaration;
  921.   begin
  922.     if RightHand
  923.      then  write(yyoutput, GiveEncodingFor(yytext))
  924.      else  begin
  925.        if (CurrentScope <> nil) and CurrentScope^.Search(@yytext, Index)
  926.         then  begin
  927.           repeat
  928.             write(yyoutput, GiveEncodingFor(yytext));
  929.             if yylex = COMMA
  930.              then  begin
  931.                write(yyoutput, ',');
  932.                yylex;
  933.              end
  934.              else  break;
  935.           until false;
  936.           yyless(0);
  937.         end
  938.         else  begin
  939.           repeat
  940.             if GlobalSection = Intr
  941.              then  write(yyoutput, EncodeNot2(yytext))
  942.              else  write(yyoutput, Encode2(yytext));
  943.             if yylex = COMMA
  944.              then  begin
  945.                writeln(yyoutput, ',');
  946.                yylex;
  947.              end
  948.              else  break;
  949.           until false;
  950.           yyless(0);
  951.         end;
  952.      end;
  953.   end; { of ParseFunctionDeclaration }
  954.  
  955.  
  956.  
  957. var
  958.   LastIdentifier,
  959.   LastPossibleTypeIdentifier,
  960.   PointerName,
  961.   TypeName: string[63];
  962. label l1;
  963. begin
  964.   Scramble := FALSE;
  965.  
  966. {* open inputfile *}
  967.   FileMode := 0;             {* open inputfile in read-only mode *}
  968.   Assign(yyinput, FromFile);
  969.   Reset(yyinput);
  970.   SetTextBuf(yyinput, Buffer, 1024);
  971.  
  972. {* open output file *}
  973.   FileMode := 1;             {* open outputfile in write-only mode *}
  974.   Assign(yyoutput, 'NUL');   {* depress output until implemenation section *}
  975.   Rewrite(yyoutput);
  976.   FileMode := 2;             {* restore filemode *}
  977.  
  978. {* initialize variables *}
  979.   yylineno := 1;
  980.   GlobalSection := Un;
  981.   Section := None;
  982.   SectionStack := New(PSectionCol, Init(50, 10));
  983.   RecordType := rtNone;
  984.   WithPushes := 0;
  985.   OpeningLevel := -1;
  986.   ParenLevel := 0;
  987.   RightHand := FALSE;
  988.   ObjectDecl := FALSE;
  989.   ObjectImpl := FALSE;
  990.   CurrentScope := New(PScopeCol, Init(200, 100));
  991.   ScopeStack := New(PCollection, Init(100, 50));
  992.   ForwardPointerCol := New(PForwardPointerCol, Init(4,4));
  993.   LastScopeIndex := -1;
  994.   AssemblerSection := FALSE;
  995.   TypeDecl := FALSE;
  996.   AbsoluteParsed := FALSE;
  997.   ConstantArray := FALSE;
  998.   TypeCastDetected := False;
  999.  
  1000. {* check if this is a unit *}
  1001.   repeat
  1002.     case yylex of
  1003.       _UNIT : break;
  1004.       _PROGRAM : begin
  1005.           Close(yyinput);
  1006.           Close(yyoutput);
  1007.           writeln('This is a program. Mangler can only mangle units. File skipped.');
  1008.           Exit;
  1009.         end;
  1010.     end; { of case }
  1011.   until IsClosed(yyinput) or eof(yyinput);
  1012.   if IsClosed(yyinput) or eof(yyinput) then  begin
  1013.     writeln('File is not a unit. File skipped.');
  1014.     Exit;
  1015.   end;
  1016.  
  1017. {* mangle *}
  1018.   write(#13, FromFile, ' (', yylineno, ')');
  1019.  
  1020.   while not eof(yyinput) do  begin
  1021.     LastRetVal := yyretval;
  1022.     case yylex of
  1023.       IDENTIFIER : begin
  1024.           LastIdentifier := yytext;
  1025.           case Section of
  1026.             Decl : ParseDeclaration;
  1027.             FuncDecl : ParseFunctionDeclaration;
  1028.           else  begin
  1029.             writeln(yyoutput, GiveEncodingFor(yytext));
  1030.           end;
  1031.           end; { of case }
  1032.         end;
  1033.       COLON, EQUAL : begin
  1034.           write(yyoutput, yytext);
  1035.           case GlobalSection of
  1036.             Intr : RightHand := TRUE;
  1037.             Impl : begin
  1038.                      if (Section = Decl) or (Section in [FuncDecl, FunctionType]) then
  1039.                        RightHand := TRUE;
  1040.                    end;
  1041.           end; { of case }
  1042.         end;
  1043.       SEMICOLON : begin
  1044.           HandleSemiColon;
  1045.         end;
  1046.       LPAREN : begin
  1047.           write(yyoutput, yytext);
  1048.           PushSection(Section);
  1049.           Inc(ParenLevel);
  1050.           OpeningLevel := -1;
  1051.           case Section of
  1052.             Decl : begin
  1053.                 if (RecordType = rtVariantRecord) or
  1054.                    ((DeclType = _CONST) and (LastRetVal = EQUAL)) then  begin
  1055.                   RightHand := FALSE;
  1056.                 end;
  1057.                 if (LastRetVal = COLON) or (LastRetVal = EQUAL) then
  1058.                   OpeningLevel := ParenLevel-1
  1059.               end;
  1060.             Func : begin
  1061.                 Section := FuncDecl;
  1062.                 RightHand := FALSE;
  1063.               end;
  1064.           else
  1065.             LastPossibleTypeIdentifier := LastIdentifier;
  1066.             if TypeCastDetected then  begin
  1067.               CurrentScope := PopScope;
  1068.               TypeCastDetected := False;
  1069.             end;
  1070.           end;  { of case }
  1071.         end;
  1072.       RPAREN : begin
  1073.           write(yyoutput, yytext);
  1074.           Dec(ParenLevel);
  1075.           case Section of
  1076.             Decl : begin
  1077.                 if LastRetVal = LPAREN then  begin
  1078.                   PushScope(CurrentScope);
  1079.                   RightHand := TRUE;
  1080.                 end;
  1081.               {* execute semicolon code at end of constant record var *}
  1082.                 if ((DeclType = _CONST) and (ParenLevel = OpeningLevel)) and not ConstantArray then
  1083.                   HandleSemiColon;
  1084.               end;
  1085.             FuncDecl : Section := Func;
  1086.           end; { of case }
  1087.           Section := PopSection;
  1088.           if TypeCastDetected then  begin
  1089.             CurrentScope := PopScope;
  1090.             TypeCastDetected := False;
  1091.           end;
  1092.         end;
  1093.       ASSIGNMENT,COMMA: begin
  1094.           write(yyoutput, yytext);
  1095.           if TypeCastDetected then  begin
  1096.             CurrentScope := PopScope;
  1097.             TypeCastDetected := False;
  1098.           end;
  1099.         end;
  1100.       DOT: begin
  1101.           write(yyoutput, yytext);
  1102.         { try to catch type casts which are record types and which
  1103.           fields are encoded }
  1104.           if LastRetVal = RPAREN then  begin
  1105.             TypeCastDetected := False;
  1106.             Scope := GetScope(LastPossibleTypeIdentifier, i);
  1107.             if (Scope <> nil) and (PMangleItem(Scope^.At(i))^.ScopeCol <> nil) then  begin
  1108.               TypeCastDetected := True;
  1109.               PushScope(CurrentScope);
  1110.               CurrentScope := Scope^.AtScope(i);
  1111.             end;
  1112.           end;
  1113.         end;
  1114.       _CONST, _TYPE, _VAR : begin
  1115.           ForwardPointerCol^.FreeAll;
  1116.           write(yyoutput, yytext, ' ');
  1117.           if not (Section in [FuncDecl, FunctionType]) then  begin
  1118.             Section := Decl;
  1119.             TypeDecl := yyretval = _TYPE;
  1120.           end;
  1121.           RightHand := FALSE;
  1122.           DeclType := yyretval;
  1123.         end;
  1124.       _RECORD : begin
  1125.           write(yyoutput, yytext, ' ');
  1126.           if Section = Decl then  begin
  1127.             RightHand := FALSE;
  1128.             RecordType := rtRecord;
  1129.           end;
  1130.         end;
  1131.       _CASE : begin
  1132.           write(yyoutput, yytext, ' ');
  1133.           case Section of
  1134.             Decl : begin
  1135.                 if RecordType in [rtRecord, rtVariantRecord] then  begin
  1136.                   RecordType := rtVariantRecord;
  1137.                   RightHand := TRUE;
  1138.                   Section := BetweenCaseAndOfDecl;
  1139.                 end;
  1140.               end;
  1141.           else  begin
  1142.             PushSection(Section);
  1143.             Section := CompoundStatement;
  1144.           end; { of case-else }
  1145.           end; { of case }
  1146.         end;
  1147.       _BEGIN : begin
  1148.           write(yyoutput, yytext, ' ');
  1149.           case Section of
  1150.             Decl, Func : Section := FuncOuter;
  1151.           else  begin
  1152.             PushSection(Section);
  1153.             Section := CompoundStatement;
  1154.           end;
  1155.           end; { of case }
  1156.         end;
  1157.       _END : begin
  1158.           if (LastRetVal <> SEMICOLON) and (LastRetVal <> _RECORD)
  1159.            then  HandleSemiColon
  1160.            else  write(yyoutput, yytext, ' ');
  1161.           case GlobalSection of
  1162.             Intr : begin
  1163.                 if ObjectDecl then  begin
  1164.                   ObjectDecl := FALSE;
  1165.                   Section := Decl;
  1166.                 end;
  1167.                 case RecordType of
  1168.                   rtRecord : if (ScopeStack^.Count = 1) and (SectionStack^.Count = 0) then
  1169.                                RecordType := rtNone;
  1170.                   rtVariantRecord : begin
  1171.                       RecordType := rtNone;
  1172.                     end;
  1173.                 end;
  1174.               end;
  1175.             Impl : begin
  1176.                 if (ScopeStack^.Count = 0) and not (Section = CompoundStatement)
  1177.                  then  begin
  1178.                    if yylex <> DOT then  begin
  1179.                      PrintError('END. expected');
  1180.                      Halt1;
  1181.                    end;
  1182.                    write(yyoutput, yytext);
  1183.                    break;
  1184.                  end
  1185.                  else  begin
  1186.                    case Section of
  1187.                      Decl : begin
  1188.                          if ObjectDecl then
  1189.                            ObjectDecl := FALSE;
  1190.                          case RecordType of
  1191.                            rtRecord : if (ScopeStack^.Count = 1) and (SectionStack^.Count = 0) then  begin
  1192.                                         RecordType := rtNone;
  1193.                                       end;
  1194.                            rtVariantRecord : begin
  1195.                                RecordType := rtNone;
  1196.                              end;
  1197.                          end;
  1198.                        end;
  1199.                      FuncOuter : begin
  1200.                        { remove every scope defined in this proc/func }
  1201.                          if CurrentScope <> nil then  begin
  1202.                            {CurrentScope^.FreeAll;}
  1203.  
  1204.                            i := 0;
  1205.                            while i < CurrentScope^.Count do  begin
  1206.                              with PMangleItem(CurrentScope^.At(i))^ do
  1207.                                if Name^ = HashedName^
  1208.                                 then  Inc(i)
  1209.                                 else  CurrentScope^.AtFree(i);
  1210.                            end;
  1211.  
  1212.                          end;
  1213.  
  1214.                          { remove scope for current function itself }
  1215.                          CurrentScope := PopScope;
  1216.  
  1217.                          if ObjectImpl and (ScopeStack^.Count = 1) then  begin
  1218.                            CurrentScope := PopScope;
  1219.                            ObjectImpl := FALSE;
  1220.                          end;
  1221.                          Section := PopSection;
  1222.                          if ScopeStack^.Count = 0 then  begin
  1223.                            if SectionStack^.Count <> 0 then  begin
  1224.                              PrintError('Section stack contains entries when ending outer function definition.');
  1225.                              Halt1;
  1226.                            end;
  1227.                          end;
  1228.                        end;
  1229.                      CompoundStatement : Section := PopSection;
  1230.                    else  PrintError('Unexpected END;');
  1231.                    end; { of case }
  1232.                  end;
  1233.               end;
  1234.           end;  { of case }
  1235.         end;
  1236.       _PROCEDURE, _FUNCTION, _CONSTRUCTOR, _DESTRUCTOR : begin
  1237. {$IFDEF ShowProcs}
  1238.           writeln(ScopeStack^.Count, '  ', yyline);
  1239. {$ENDIF}
  1240.           write(yyoutput, yytext, ' ');
  1241.           if not ((Section = Decl) and RightHand and not ObjectDecl)
  1242.            then  yylex  {* get name *}
  1243.            else  yytext := '';
  1244.           Section := Func;
  1245.           if yytext = '' then  begin
  1246.             Section := FunctionType;
  1247.             continue;
  1248.           end;
  1249.           case GlobalSection of
  1250.             Intr : begin
  1251.                 writeln(yyoutput, yytext);
  1252.                 if yytext = ''
  1253.                  then  CurrentScope^.InsertIntrIdentifier(ObjectName, LastScopeIndex)
  1254.                  else  CurrentScope^.InsertIntrIdentifier(yytext, LastScopeIndex);
  1255.                 PushScope(CurrentScope);
  1256.                 CurrentScope := CurrentScope^.AtScope(LastScopeIndex);
  1257.               end;
  1258.             Impl : begin
  1259.                 if yytext = '' then
  1260.                   continue;
  1261.                 if not ObjectDecl then
  1262.                   PushSection(Section);
  1263.                 if (CurrentScope <> nil) and CurrentScope^.Search(@yytext, Index)
  1264.                  then  begin
  1265.                  {* already declared *}
  1266.                    write(yyoutput, CurrentScope^.AtHashedName(Index));
  1267.                    PushScope(CurrentScope);
  1268.                    CurrentScope := CurrentScope^.AtScope(Index);
  1269.                    if yylex = DOT
  1270.                     then  begin
  1271.                     {* object declaration *}
  1272.                       ObjectImpl := TRUE;
  1273.                       write(yyoutput, yytext);
  1274.                       yylex;      {* get object name *}
  1275.                       CurrentScope^.Search(@yytext, LastScopeIndex);
  1276.                       writeln(yyoutput, CurrentScope^.AtHashedName(LastScopeIndex));
  1277.                       PushScope(CurrentScope);
  1278.                       CurrentScope := CurrentScope^.AtScope(LastScopeIndex);
  1279.                     end
  1280.                     else  begin
  1281.                     {* normal funtion or procedure *}
  1282.                       writeln(yyoutput);
  1283.                       yyless(0);
  1284.                       LastScopeIndex := Index;
  1285.                     end;
  1286.                  end
  1287.                  else  begin
  1288.                  {* new definition *}
  1289.                    if ObjectDecl
  1290.                     then  writeln(yyoutput, EncodeNot(yytext))
  1291.                     else  writeln(yyoutput, Encode(yytext));
  1292.                  end;
  1293.               end;
  1294.           end;  { of case }
  1295.         end;
  1296.       _FORWARD, _EXTERNAL : begin
  1297.           write(yyoutput, yytext);
  1298.           CurrentScope := PopScope;
  1299.           Section := PopSection;
  1300.         end;
  1301.       _INLINE : begin
  1302.           write(yyoutput, yytext);
  1303.           if (Section = Func) or (GlobalSection= Intr) then
  1304.             Section := Inlin;
  1305.         end;
  1306.       _VIRTUAL : begin
  1307.           write(yyoutput, yytext);
  1308.           Section := Decl;
  1309.           RightHand := FALSE;
  1310.           yylex;   {* get SEMICOLON *}
  1311.           writeln(yyoutput, yytext);
  1312.         end;
  1313.       _OBJECT : begin
  1314.           if SectionStack^.Count <> 0 then  begin
  1315.             PrintError('Section stack contains entries when starting to parse object definition.');
  1316.             Halt1;
  1317.           end;
  1318.           if ScopeStack^.Count > 1 then  begin
  1319.             PrintError('Scope stack contains two or more entries when starting to parse object definition.');
  1320.             Halt1;
  1321.           end;
  1322.           write(yyoutput, yytext, ' ');
  1323.           Section := Decl;
  1324.           RightHand := FALSE;
  1325.           ObjectDecl := TRUE;
  1326.           CreateCurrentScope;
  1327.           if GlobalSection in [Intr, Impl] then  begin
  1328.             if yylex = LPAREN
  1329.              then  begin
  1330.                write(yyoutput, yytext);
  1331.                yylex;        {* read parent *}
  1332.                Scope := GetScope(yytext, Index);
  1333.                write(yyoutput, GiveEncodingFor(yytext));
  1334.                yylex;        {* read RPAREN *}
  1335.                write(yyoutput, yytext);
  1336.                if (Scope <> nil) and (Scope^.AtScope(Index) <> nil) then  begin
  1337.                  Scope := Scope^.AtScope(Index);
  1338.                  for i := 0 to Scope^.Count-1 do
  1339.                    CurrentScope^.Insert(Scope^.At(i));
  1340.                end;
  1341.              end
  1342.              else  yyless(0);
  1343.           end;
  1344.         end;
  1345.       _PRIVATE : begin
  1346.           writeln(yyoutput, yytext);
  1347.           Section := Decl;
  1348.           RightHand := FALSE;
  1349.         end;
  1350.  
  1351.       _INHERITED : begin
  1352.           write(yyoutput, yytext, ' ');
  1353.           yylex;   {* get identifier, but mangle it not *}
  1354.           write(yyoutput, yytext, ' ');
  1355.         end;
  1356.       _WITH : begin
  1357.           write(yyoutput, yytext, ' ');
  1358.           PushSection(Section);
  1359.           WithPushes := 0;
  1360.           repeat
  1361.             yylex;
  1362.             Scope := GetScope(yytext, i);
  1363.             if Scope <> nil then  begin
  1364.               PushScope(CurrentScope);
  1365.               CurrentScope := Scope^.AtScope(i);
  1366.               Inc(WithPushes);
  1367.             end;
  1368.             write(yyoutput, GiveEncodingFor(yytext));
  1369.           l1:
  1370.             case yylex of
  1371.               _DO : break;
  1372.               COMMA : write(yyoutput, yytext);
  1373.               UPARROW : begin
  1374.                   write(yyoutput, yytext);
  1375.                   case yylex of
  1376.                     _DO : break;
  1377.                     COMMA : write(yyoutput, yytext);
  1378.                     LBRAC : begin
  1379.                                repeat
  1380.                                  writeln(yyoutput, yytext);
  1381.                                until yylex = RBRAC;
  1382.                                writeln(yyoutput, yytext);
  1383.                                if yylex = _DO
  1384.                                 then  begin
  1385.                                   write(yyoutput, ' ', yytext);
  1386.                                   break;
  1387.                                 end
  1388.                                 else  yyless(0);
  1389.                              end;
  1390.                   end; { of case }
  1391.                 end;
  1392.               LPAREN : begin
  1393.                   write(yyoutput, yytext);
  1394.                 {* function or type override encountered *}
  1395.                   Paren := 1;
  1396.                   repeat
  1397.                     case yylex of
  1398.                       LPAREN : begin Inc(Paren); write(yyoutput, yytext); end;
  1399.                       RPAREN : begin Dec(Paren);  write(yyoutput, yytext); end;
  1400.                       IDENTIFIER : write(yyoutput, GiveEncodingFor(yytext));
  1401.                     else  write(yyoutput, yytext);
  1402.                     end;
  1403.                   until Paren = 0;
  1404.                   goto l1;
  1405.                 end;
  1406.               LBRAC : begin
  1407.                   write(yyoutput, yytext);
  1408.                 {* array encountered *}
  1409.                   repeat
  1410.                     case yylex of
  1411.                       IDENTIFIER : writeln(yyoutput, GiveEncodingFor(yytext));
  1412.                       RBRAC : break;
  1413.                     else  write(yyoutput, yytext);
  1414.                     end; { of case }
  1415.                   until false;
  1416.                   write(yyoutput, yytext);
  1417.                   goto l1;
  1418.                 end;
  1419.             else  begin
  1420.               PrintError('Unexpected WITH form.');
  1421.               Halt1;
  1422.             end;
  1423.             end; { of case }
  1424.           until false;
  1425.           write(yyoutput, ' DO ');
  1426.           Section := WithStatement;
  1427.         end;
  1428.       _ASM : ParseAsm;
  1429.       _ASSEMBLER : begin
  1430.           write(yyoutput, yytext);
  1431.           AssemblerSection := TRUE;
  1432.         end;
  1433.       _FOR, _WHILE : begin
  1434.           write(yyoutput, yytext, ' ');
  1435.         end;
  1436.       _ABSOLUTE : begin
  1437.           write(yyoutput, ' ', yytext, ' ');
  1438.           AbsoluteParsed := TRUE;
  1439.         end;
  1440.       _DO, _OF : begin
  1441.           write(yyoutput, ' ', yytext, ' ');
  1442.           if Section = BetweenCaseAndOfDecl then
  1443.             Section := Decl;
  1444.         end;
  1445.       CHARACTER_STRING : begin
  1446.           write(yyoutput, yytext);
  1447.           while yylex = _CHAR do
  1448.             write(yyoutput, yytext);
  1449.           yyless(0);
  1450.         end;
  1451.       _CHAR : write(yyoutput, yytext);
  1452.       UPARROW : begin
  1453.           write(yyoutput, yytext);
  1454.           if GlobalSection = Impl then  begin
  1455.             if (Section = Decl) and TypeDecl
  1456.               then  begin
  1457.                 yylex;      {* get identifier *}
  1458.  
  1459.                 {* if already declared, no problem, else it is a forward *}
  1460.                 {* pointer which should not be scrambled *}
  1461.                 if GetScope(yytext, Index) = nil
  1462.                   then  begin
  1463.                     PointerName := LastIdentifier;
  1464.                     TypeName := yytext;
  1465.                     with ScopeStack^ do
  1466.                       PScopeCol(At(Count-1))^.InsertIdentifier(yytext, Index);
  1467.                     ForwardPointerCol^.InsertItem(PointerName, TypeName);
  1468.                   end
  1469.                   else  begin
  1470.                   end;
  1471.  
  1472.                 yyless(0)   {* return read characters *}
  1473.               end
  1474.               else  begin
  1475.                 Scope := GetScope(LastIdentifier, i);
  1476.                 if Scope <> nil then  begin
  1477.                   PushScope(CurrentScope);
  1478.                   CurrentScope := Scope^.AtScope(i);
  1479.                   if (CurrentScope <> nil) and (CurrentScope^.Count > 0)
  1480.                     then
  1481.                       TypeCastDetected := True   { ahem }
  1482.                     else
  1483.                       CurrentScope := PopScope;
  1484.                 end;
  1485.               end;
  1486.           end;
  1487.         end;
  1488.       _ARRAY : begin
  1489.           writeln(yyoutput, yytext);
  1490.           ConstantArray := DeclType = _CONST;
  1491.         end;
  1492.       _FAR, _NEAR : begin
  1493.           write(yyoutput, yytext);
  1494.           if yylex = SEMICOLON
  1495.            then  write(yyoutput, ';')
  1496.            else  begin
  1497.              write(yyoutput, ' ');
  1498.              yyless(0);
  1499.            end;
  1500.         end;
  1501.       _LABEL : begin
  1502.           Section := LabelStatement;
  1503.           write(yyoutput, yytext, ' ');
  1504.         end;
  1505.       DIRECTIVE : begin
  1506.           write(yyoutput, yytext);
  1507.         end;
  1508.       _INTERFACE : begin
  1509.           write(yyoutput, yytext, ' ');
  1510.           GlobalSection := Intr;
  1511.         end;
  1512.       _IMPLEMENTATION : begin
  1513.           if SectionStack^.Count <> 0 then  begin
  1514.             PrintError('Internal error: section stack contains entries when starting to parse implementation.');
  1515.             Halt1;
  1516.           end;
  1517. (*
  1518.           if ScopeStack^.Count <> 0 then  begin
  1519.             PrintError('Internal error: scope stack contains entries when starting to parse implementation.');
  1520.             Halt1;
  1521.           end;
  1522. *)
  1523.  
  1524.         {* close temporary output file *}
  1525.           Close(yyoutput);
  1526.  
  1527.         {* open temporary output file for mangled implementation section *}
  1528.           FileMode := 1;             {* open outputfile in write-onlymode *}
  1529.           Assign(yyoutput, ToFile);
  1530.           Rewrite(yyoutput);
  1531.           FileMode := 2;             {* restore filemode *}
  1532.  
  1533.           ImplementationLineNumber := yylineno;
  1534.           write(yyoutput, yytext, ' ');
  1535.           GlobalSection := Impl;
  1536.           Section := None;
  1537.         end;
  1538.     else  writeln(yyoutput, yytext);
  1539.     end;  { of case }
  1540.   end;  { of while }
  1541.  
  1542.   if ScopeStack^.Count <> 0 then  begin
  1543.     PrintError('Unexpected end of file');
  1544.     Close(yyinput);
  1545.     Close(yyoutput);
  1546.     Exit;
  1547.   end;
  1548.  
  1549. {* dispose variables *}
  1550. (* can't be disposed
  1551.   Dispose(CurrentScope, Done);
  1552. *)
  1553.   Dispose(ScopeStack, Done);
  1554.   Dispose(SectionStack, Done);
  1555.  
  1556. {* close files *}
  1557.   WriteProgress;
  1558.   Close(yyinput);
  1559.   Close(yyoutput);
  1560.  
  1561.   Scramble := TRUE;
  1562. end;
  1563.  
  1564.  
  1565. var
  1566.   crunched_line_no : integer;
  1567.  
  1568. procedure Crunch(OrgFile, FromFile, ToFile : FNameStr);
  1569. {* rewrites a file in as few lines as possible *}
  1570. const
  1571.   BufferSize = 1024;
  1572. var
  1573.   Buffer : array[1..BufferSize] of char;
  1574.   LineNumber : word;
  1575.   d, s : string;
  1576. begin
  1577.   Assign(yyoutput, ToFile);
  1578.   Rewrite(yyoutput);
  1579.   writeln(yyoutput, '(* This file was mangled by Mangler ', Version, ' (c) Copyright 1993-1994 by Berend de Boer *)');
  1580.  
  1581. {* write interface section *}
  1582.   Assign(yyinput, OrgFile);
  1583.   Reset(yyinput);
  1584.   SetTextBuf(yyinput, Buffer, BufferSize);
  1585.   LineNumber := 2;
  1586.   while LineNumber <> ImplementationLineNumber do  begin
  1587.     readln(yyinput, s);
  1588.     writeln(yyoutput, s);
  1589.     Inc(LineNumber);
  1590.   end;
  1591.   Close(yyinput);
  1592.  
  1593. {* rewrite mangled implementation section in fewer lines *}
  1594.   Assign(yyinput, FromFile);
  1595.   Reset(yyinput);
  1596.   SetTextBuf(yyinput, Buffer, BufferSize);
  1597.  
  1598. {* and crunch it *}
  1599.   d := '';
  1600.   crunched_line_no := 1;
  1601.   while not eof(yyinput) do  begin
  1602.     readln(yyinput, s);
  1603.     if length(d) + length(s) <= LineWidth
  1604.      then  begin
  1605.        if d[length(d)] = ';'
  1606.         then  d := d + s
  1607.         else
  1608.           if s <> '' then  d := d + ' ' + s;
  1609.      end
  1610.      else  begin
  1611.        Inc(crunched_line_no);
  1612.        writeln(yyoutput, d);
  1613.        d := s;
  1614.      end;
  1615.   end;  { of while }
  1616.   writeln(yyoutput, d);
  1617.  
  1618. {* close files *}
  1619.   Close(yyinput);
  1620.   Close(yyoutput);
  1621. end;
  1622.  
  1623.  
  1624.  
  1625. function MatchFileNames(const Source, Dest : PathStr) : string;
  1626. {* Source and Dest are made equal everywhere Dest contains a '?' *}
  1627. var
  1628.   p : word;
  1629.   i : integer;
  1630.   SourceDir, DestDir : DirStr;
  1631.   SourceName, DestName : NameStr;
  1632.   SourceExt, DestExt : ExtStr;
  1633. begin
  1634.   FSplit(Source, SourceDir, SourceName, SourceExt);
  1635.   FSplit(Dest, DestDir, DestName, DestExt);
  1636.  
  1637. {* match name *}
  1638.   if DestName = ''
  1639.    then  DestName := SourceName
  1640.    else  begin
  1641.      p := Pos('*', DestName);
  1642.      if p > 0
  1643.       then  begin
  1644.         Delete(DestName, p, length(DestName));
  1645.         DestName := DestName + Copy(SourceName, p, length(SourceName));
  1646.       end
  1647.       else  begin
  1648.         p := Pos('?', DestName);
  1649.         if p > 0 then  begin
  1650.           for i := p to length(DestName) do
  1651.             if (DestName[i] = '?') and (i <= length(SourceName)) then
  1652.               DestName[i] := SourceName[i]
  1653.         end;
  1654.       end;
  1655.    end;
  1656.  
  1657. {* match ext *}
  1658.   if DestExt = ''
  1659.    then  DestExt := SourceExt
  1660.    else  begin
  1661.      p := Pos('*', DestExt);
  1662.      if p > 0
  1663.       then  begin
  1664.         Delete(DestExt, p, length(DestExt));
  1665.         DestExt := DestExt + Copy(SourceExt, p, length(SourceExt));
  1666.       end
  1667.       else  begin
  1668.         p := Pos('?', DestExt);
  1669.         if p > 0 then  begin
  1670.           for i := p to length(DestExt) do
  1671.             if (DestExt[i] = '?') and (i <= length(SourceExt)) then
  1672.               DestExt[i] := SourceExt[i]
  1673.         end;
  1674.       end;
  1675.    end;
  1676.  
  1677.   MatchFileNames := DestDir + DestName + DestExt;
  1678. end;
  1679.  
  1680.  
  1681.  
  1682. var
  1683.   File1, File2 : byte;
  1684.   destDir : DirStr;
  1685.   sourceName, destName : NameStr;
  1686.   sourceExt, destExt : ExtStr;
  1687.   tmpFileName : PathStr;
  1688.   DestFileName : PathStr;
  1689.   s : string;
  1690.   code : word;
  1691.  
  1692. begin
  1693.   Close(Output);
  1694.   Assign(Output, '');
  1695.   Rewrite(Output);
  1696.   writeln(#13+'Source code Mangler ', Version, ', (c) Copyright 1993-1994 by Berend de Boer.');
  1697. {$IFDEF Debug}
  1698.   InitBBError('MANGLER.LOG', TRUE);
  1699.   InitMemCheck(mfStandard);
  1700.   InitObjMemory;
  1701.   InitPMD(dfStandard);
  1702. {$ENDIF}
  1703.   if (ParamCount < 2) or (ParamCount > 3) then  begin
  1704.     writeln('Parameter error.');
  1705.     writeln('Usage:');
  1706.     writeln('MANGLER [options] sourcefile(s) destfile(s)');
  1707.     writeln('Wildcards are supported.');
  1708.     writeln('Options:');
  1709.     writeln('-w[number]  outputted maximum line width');
  1710.     Halt(1);
  1711.   end;
  1712.  
  1713.   if ParamCount = 3
  1714.    then  begin
  1715.      if Copy(ParamStr(1), 1, 2) <> '-w' then  begin
  1716.        writeln('Error parsing options.');
  1717.        Halt(1);
  1718.      end;
  1719.      s := ParamStr(1);
  1720.      System.Delete(s, 1, 2);
  1721.      Val(s, LineWidth, code);
  1722.      if code <> 0 then  begin
  1723.        writeln('Incorrect line width.');
  1724.        Halt(1);
  1725.      end;
  1726.      File1 := 2;
  1727.      File2 := 3;
  1728.    end
  1729.    else  begin     {* ParamCount = 2 *}
  1730.      File1 := 1;
  1731.      File2 := 2;
  1732.    end;
  1733.  
  1734.   if ParamStr(File1) = ParamStr(File2) then  begin
  1735.     writeln('Source file(s) equal(s) destination file(s). Mangler halted.');
  1736.     Halt(1);
  1737.   end;
  1738.  
  1739. {* install error procedure *}
  1740.   ExitSave := ExitProc;
  1741.   ExitProc := @ExitHandler;
  1742.  
  1743. {* close files opened by LexLib *}
  1744.   Close(yyinput);
  1745.   Close(yyoutput);
  1746.  
  1747.   Randomize;
  1748.  
  1749. {* split source name *}
  1750.   FSplit(ParamStr(File1), sourceDir, sourceName, sourceExt);
  1751.  
  1752. {* split dest name *}
  1753.   FSplit(ParamStr(File2), destDir, destName, destExt);
  1754.  
  1755. {* FindFirst/FindNext loop *}
  1756.   FindFirst(ParamStr(File1), Archive, DirInfo);
  1757.  
  1758.   if DosError <> 0 then
  1759.     writeln('Source file(s) not found.');
  1760.  
  1761.   while DosError = 0 do  begin
  1762.  
  1763.   {* name of intermediate file *}
  1764.     tmpFileName := MatchFileNames(DirInfo.Name, destDir + destName + '.$$$');
  1765.  
  1766.   {* destination filename *}
  1767.     DestFileName := MatchFileNames(DirInfo.Name, destDir+destName+destExt);
  1768.  
  1769.     if sourceDir+DirInfo.Name = DestFileName
  1770.      then  writeln('Source file equals destination file. File ', sourceDir+DirInfo.Name, ' skipped.')
  1771.      else  begin
  1772.  
  1773.      {* Pass 1, scramble file *}
  1774.        writeln('Pass 1: Scrambling');
  1775.        write(DirInfo.Name, '(0)');
  1776.  
  1777.      {* scramble to temporary file *}
  1778.        if Scramble(sourceDir+DirInfo.Name, tmpFileName) then  begin
  1779.  
  1780. {$IFDEF Crunch}
  1781.        {* pass 2, rewrite the mangled code in as few lines as possible *}
  1782.          writeln;
  1783.          writeln('Pass 2: Crunching');
  1784.  
  1785.        {* open temporary file and create the real destination file *}
  1786.          Crunch(sourceDir+DirInfo.Name, tmpFileName, DestFileName);
  1787.          writeln('File crunched from ', yylineno-1, ' lines to ', crunched_line_no, ' lines');
  1788.          Erase(yyinput);     {* erase temporary file *}
  1789. {$ENDIF}
  1790.        end;
  1791.      end;
  1792.  
  1793.     FindNext(DirInfo);
  1794.   end;  { of while }
  1795.  
  1796. end.
  1797.